package com.lieve.bpm.config;

import com.lieve.bpm.db.DistributedIdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.activiti.engine.impl.db.DbSqlSessionFactory;
import org.activiti.engine.impl.persistence.StrongUuidGenerator;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ActivitiProperties;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

/**
 * @author sunyoboy
 * 2020/10/24
 */
@Slf4j
//@Component
//@EnableConfigurationProperties(ActivitiProperties.class)
public class DataSourceProcessEngineConfiguration extends StandaloneProcessEngineConfiguration {

    public static final String CUSTOM_MYBATIS_MAPPING_FILE = "com/lieve/mapper/mappings.xml";

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.password}")
    private String password;


    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;
    /*
    @Override
    protected void init() {
        super.init();
    }*/


    @Override
    protected InputStream getMyBatisXmlConfigurationSteam() {
        log.debug("getMyBatisXmlConfigurationSteam");
        return getResourceAsStream(CUSTOM_MYBATIS_MAPPING_FILE);
    }

    @Override
    protected void initSqlSessionFactory() {
        if (sqlSessionFactory == null) {
            InputStream inputStream = null;
            try {
                inputStream = getMyBatisXmlConfigurationSteam();

                // update the jdbc parameters to the configured ones...
                Environment environment = new Environment("default", transactionFactory, dataSource);
                Reader reader = new InputStreamReader(inputStream);
                Properties properties = new Properties();
                properties.put("prefix", databaseTablePrefix);
                if (super.databaseType != null) {
                    properties.put("limitBefore", DbSqlSessionFactory.databaseSpecificLimitBeforeStatements.get(databaseType));
                    properties.put("limitAfter", DbSqlSessionFactory.databaseSpecificLimitAfterStatements.get(databaseType));
                    properties.put("limitBetween", DbSqlSessionFactory.databaseSpecificLimitBetweenStatements.get(databaseType));
                    properties.put("limitOuterJoinBetween", DbSqlSessionFactory.databaseOuterJoinLimitBetweenStatements.get(databaseType));
                    properties.put("orderBy", DbSqlSessionFactory.databaseSpecificOrderByStatements.get(databaseType));
                    properties.put("limitBeforeNativeQuery", ObjectUtils.toString(DbSqlSessionFactory.databaseSpecificLimitBeforeNativeQueryStatements.get(databaseType)));
                }

                Configuration configuration = initMybatisConfiguration(environment, reader, properties);
                sqlSessionFactory = new DefaultSqlSessionFactory(configuration);

            } catch (Exception e) {
                throw new ActivitiException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e);
            } finally {
                IoUtil.closeSilently(inputStream);
            }
        }
    }

    @Override
    protected void initIdGenerator() {
        if (idGenerator == null) {
            StrongUuidGenerator dbIdGenerator = new StrongUuidGenerator();
            /*dbIdGenerator.setIdBlockSize(idBlockSize);
            dbIdGenerator.setCommandExecutor(idGeneratorCommandExecutor);
            dbIdGenerator.setCommandConfig(getDefaultCommandConfig().transactionRequiresNew());*/
            idGenerator = dbIdGenerator;
        }
    }

    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
                .url(url)
                .driverClassName(driverClassName)
                .password(password)
                .username(username)
                .build();
    }

    @Bean
    @ConditionalOnMissingBean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /*@Bean
    public ProcessEngineFactoryBean processEngine(SpringProcessEngineConfiguration configuration) throws Exception {
        return super.springProcessEngineBean(configuration);
    }*/


    /*
    @Bean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(
            DataSource dataSource,
            PlatformTransactionManager transactionManager,
            SpringAsyncExecutor springAsyncExecutor) throws IOException {

        return this.baseSpringProcessEngineConfiguration(dataSource, transactionManager, springAsyncExecutor);
    }*/


    @Bean
    @ConditionalOnMissingBean
    public SpringProcessEngineConfiguration processEngineConfiguration() {
        SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
        DataSource dataSource = dataSource();
        processEngineConfiguration.setDataSource(dataSource);
        processEngineConfiguration.setTransactionManager(transactionManager(dataSource));
        processEngineConfiguration.setProcessEngineName(ProcessEngines.NAME_DEFAULT);



                /*
        //设置全局事件监听
        processEngineConfiguration.setTypedEventListeners(this.getGlobalActivitiEventListener());
        //重写节点行为
        processEngineConfiguration.setActivityBehaviorFactory(new CdpActivityBehaviorFactory());*/
        //设置主键生成
        processEngineConfiguration.setIdGenerator(new StrongUuidGenerator());
        /*//设置函数
        processEngineConfiguration.setBeans(FunctionFactory.getFunctionBeans());*/
        Set<String> xmlMappersSet = new HashSet<>();
        xmlMappersSet.add("com/lieve/bpm/mapper/User2.xml");
        // processEngineConfiguration.setCustomMybatisXMLMappers(xmlMappersSet);
        this.dataSource = dataSource;
        initTransactionFactory();
        initSqlSessionFactory();
        return processEngineConfiguration;
    }

}